#include "app_buffer.h"
#include <stdlib.h>
#include <string.h>
#include "log/log.h"

// 创建小缓冲区
SubBuffer *sub_buffer_init(int size) {
    SubBuffer *sub_buffer = malloc(sizeof(SubBuffer));
    sub_buffer->ptr = malloc(size);
    sub_buffer->total_size = size;
    sub_buffer->len = 0;

    return sub_buffer;
}

Buffer *app_buffer_init(int size)
{
    Buffer *buffer = malloc(sizeof(Buffer));
    buffer->sub_buffers[0] = sub_buffer_init(size);
    buffer->sub_buffers[1] = sub_buffer_init(size);
    buffer->read_index = 0;
    buffer->write_index = 1;
    // 初始化读和写锁
    pthread_mutex_init(&buffer->read_lock, NULL);
    pthread_mutex_init(&buffer->write_lock, NULL);

    return buffer;
}

void app_buffer_free(Buffer *buffer)
{
    free(buffer->sub_buffers[0]->ptr);
    free(buffer->sub_buffers[1]->ptr);
    free(buffer->sub_buffers[0]);
    free(buffer->sub_buffers[1]);

    pthread_mutex_destroy(&buffer->read_lock);
    pthread_mutex_destroy(&buffer->write_lock);
    
    free(buffer);
}

int app_buffer_write(Buffer *buffer, char *data, int data_len)
{
    // 检查data_len： 后面用一个字节存储数据长度（不能超过255）
    if (data_len > 255) {
        log_error("写入的数据大小不能超过255");
        return -1;
    }

    // 在准备写入数据前加 写锁
    log_debug("在准备写入数据前加 写锁");
    pthread_mutex_lock(&buffer->write_lock);

    // 得到写缓冲区
    SubBuffer *w_buffer = buffer->sub_buffers[buffer->write_index];

    // 检查剩余空间是否足够
    if (w_buffer->total_size-w_buffer->len < data_len+1) {
        log_error("写缓冲区剩余空间不足");
        pthread_mutex_unlock(&buffer->write_lock);
        return -1;
    }

    // 写数据(先写数据长度，再写数据本身)
    w_buffer->ptr[w_buffer->len] = data_len; // 用一个字节存储数据长度（不能超过255）
    memcpy(w_buffer->ptr+w_buffer->len+1, data, data_len);

    // 更新写缓冲区的len
    w_buffer->len += data_len + 1;

    // 写完数据后解 写锁
    log_debug("写完数据后解 写锁");
    pthread_mutex_unlock(&buffer->write_lock);

    return 0;
}

static void switch_sub_buffer (Buffer *buffer) { // 写过程中不能切换，切换过程中不能写
    //  在准备切换前，加写锁
    log_debug("在准备切换前加写锁");
    pthread_mutex_lock(&buffer->write_lock);

    int temp = buffer->read_index;
    buffer->read_index = buffer->write_index;
    buffer->write_index = temp;
    
    // 切换完，解写锁
    log_debug("切换完，解写锁");
    pthread_mutex_unlock(&buffer->write_lock);
}

int app_buffer_read(Buffer *buffer, char *data_buf, int buf_size)
{

    // 在准备读取数据前加 读锁
    log_debug("在准备读取数据前加 读锁");
    pthread_mutex_lock(&buffer->read_lock);

    // 得到读缓冲区
    SubBuffer *r_buffer = buffer->sub_buffers[buffer->read_index];
    // 如果读缓冲区为空，切换读写缓冲区， 如果还是空的，返回-1
    if (r_buffer->len == 0) {
        switch_sub_buffer(buffer);
        // 重新得到读缓冲区
        r_buffer = buffer->sub_buffers[buffer->read_index];
        if (r_buffer->len == 0) {
            log_error("读缓冲区为空, 没有数据可读");
            pthread_mutex_unlock(&buffer->read_lock);
            return -1;
        }
    }

    // 从中读取第一帧数据(数据长度+数据本身)，并保存到data_buf， 并将剩余的数据移动最左边
    int data_len = r_buffer->ptr[0];
    log_debug("--data_len: %d", data_len);
    // 检查data_buf空间是否足够
    if (data_len>buf_size) {
        log_error("data_buf空间不足");
        pthread_mutex_unlock(&buffer->read_lock);
        return -1;
    }

    memcpy(data_buf, r_buffer->ptr+1, data_len);
    memmove(r_buffer->ptr, r_buffer->ptr+data_len+1, r_buffer->len-data_len-1);

    // 更新读缓冲区的len
    r_buffer->len -= data_len + 1;


    // 读取完数据后解 读锁
    log_debug("读取完数据后解 读锁");
    pthread_mutex_unlock(&buffer->read_lock);

    // 返回读取的数据长度
    return data_len;
}
